package nz.ac.massey.doi_information_extractor.parser;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import nz.ac.massey.doi_information_extractor.data.Author;
import nz.ac.massey.doi_information_extractor.data.AuthorList;
import nz.ac.massey.doi_information_extractor.data.Publication;

// This is a basic parser for the www.bibsonomy.com website. It gets BibTex format and tries to parse it.
// Note that this plugin has no real error detection or correction yet. It shouldn't be trusted.
public class BibsonomyPlugin implements PluginInterface {

	private String doi;
	public Publication result = new Publication();

	public BibsonomyPlugin(String inputdoi) {
		this.doi = inputdoi;
	}

	@Override
	public void getInformationFromDOI(String doi) throws PublicationNotFoundException,
			IOException {

		// Get the page with search results for the DOI.
		URL searchPage;
		try {
			searchPage = new URL("http://www.bibsonomy.org/search/"
					+ URLEncoder.encode(doi, "UTF-8"));
		} catch (MalformedURLException e) {
			throw new PublicationNotFoundException(e.getMessage());
		} catch (UnsupportedEncodingException e) {
			throw new PublicationNotFoundException(e.getMessage());
		}

		URLConnection listPage = searchPage.openConnection();

		BufferedInputStream buffer = new BufferedInputStream(
				listPage.getInputStream());

		StringBuilder builder = new StringBuilder();
		int byteRead;
		while ((byteRead = buffer.read()) != -1){
			builder.append((char) byteRead);
		}
		buffer.close();

		// Put the source together.
		String source = builder.toString();

		// This expression is used to find the occurance of the BibTex link for
		// the result.
		String expr = "<a title=\"show this publication in BibTeX format\" href=\".*\">BibTeX</a>";

		Pattern patt = Pattern.compile(expr, Pattern.DOTALL
				| Pattern.UNIX_LINES);
		Matcher m = patt.matcher(source);
		while (m.find()) {
			source = source.substring(m.start(), m.end());
		}

		// Get the BibTex page for the search result.
		String[] slicedAddress = source.split("\"");
		URL finalAddress = new URL("http://www.bibsonomy.org"
				+ slicedAddress[3]);

		try {
			URLConnection resultsohgosh = finalAddress.openConnection();

			BufferedInputStream lastBuffer = new BufferedInputStream(
					resultsohgosh.getInputStream());

			StringBuilder lastBuilder = new StringBuilder();
			int readByte;
			while ((readByte = lastBuffer.read()) != -1){
				lastBuilder.append((char) readByte);
			}
			lastBuffer.close();
			String lastSource = lastBuilder.toString();

			if (lastSource == null)
				throw new PublicationNotFoundException();

			// Fill title..

			this.result.setArticleTitle(getTitle(lastSource));

			// Fill out the authors..

			this.result.setAuthors(getAuthors(lastSource));

			// Fill date..

			this.result.setDate(getDate(lastSource));

			// Fill journal..

			this.result.setPublicationTitle(getJournal(lastSource));

			// Fill pages..

			this.result.setPageNumbers(getPageNumbers(lastSource));

			// Fill volume number..

			this.result.setVolumeNumber(getVolume(lastSource));
			
			// Fill issue number.. 
			
			this.result.setEdition(getIssueNumber(lastSource));

		} catch (Exception e) {
			throw new PublicationNotFoundException(e.getMessage());
		}
	}
	
	// The following methods simply use the Pattern and Matcher classes to parse
	// the BibTex format string they're given.
	private String getIssueNumber(String source) {
		
		String issueNumber = "";
		Pattern issuePatt = Pattern.compile("number = .*,",
				Pattern.UNIX_LINES);
		Matcher issueMat = issuePatt.matcher(source);
		while (issueMat.find()) {
			issueNumber = source.substring(issueMat.start(), issueMat.end());
		}
		if (issueNumber != "") {
			issueNumber = issueNumber.substring(9, issueNumber.length() - 1);
		}
		return issueNumber;
	}

	private String getTitle(String source) {
		String articleTitle = "";
		Pattern titlePatt = Pattern.compile("title = \\{.*\\}",
				Pattern.UNIX_LINES);
		Matcher titleMat = titlePatt.matcher(source);
		while (titleMat.find()) {
			articleTitle = source.substring(titleMat.start(), titleMat.end());
		}
		if (articleTitle != "") {
			articleTitle = articleTitle.substring(9, articleTitle.length() - 1);
		}
		return articleTitle;
	}

	private AuthorList getAuthors(String source) {
		AuthorList authorsList = new AuthorList();
		String authorsString = "";
		Pattern authorsPatt = Pattern.compile("author = \\{.*\\}",
				Pattern.UNIX_LINES);
		Matcher authorsMat = authorsPatt.matcher(source);
		while (authorsMat.find()) {
			authorsString = source.substring(authorsMat.start(),
					authorsMat.end());
		}
		if (authorsString != "") {
			authorsString = authorsString.substring(10,
					authorsString.length() - 1);

			String[] authorsFurtherString = authorsString.split(" ");

			// This is a little more tricky than the other methods, as it has to
			// fill the AuthorList with Author objects. It will make mistakes if
			// someone is called 'and'.
			Author tempAuthor = new Author();
			for (int i = 0; i < authorsFurtherString.length; i++) {

				if (authorsFurtherString[i].equals("and")) {
					continue;
				}

				if (tempAuthor.getAuthorFirstName() == "") {
					tempAuthor.setAuthorFirstName(authorsFurtherString[i]);
				} else {
					tempAuthor.setAuthorLastName(authorsFurtherString[i]);
					authorsList.add(tempAuthor);
					tempAuthor = new Author();
				}
			}
		}
		return authorsList;
	}

	private String getDate(String source) {
		String articleDate = "";
		Pattern datePatt = Pattern.compile("date = \\{.*\\}",
				Pattern.UNIX_LINES);
		Matcher dateMat = datePatt.matcher(source);
		while (dateMat.find()) {
			articleDate = source.substring(dateMat.start(), dateMat.end());
		}
		if (articleDate != "") {
		articleDate = articleDate.substring(8, articleDate.length() - 1);
		}

		return articleDate;
	}

	private String getJournal(String source) {
		String articleJournal = "";
		Pattern journalPatt = Pattern.compile("journal = \\{.*\\}",
				Pattern.UNIX_LINES);
		Matcher journalMat = journalPatt.matcher(source);
		while (journalMat.find()) {
			articleJournal = source.substring(journalMat.start(),
					journalMat.end());
		}
		if (articleJournal != "") {
		articleJournal = articleJournal.substring(11,
				articleJournal.length() - 1);
		}
		return articleJournal;
	}

	private String getPageNumbers(String source) {
		String articlePageNumbers = "";
		Pattern journalPatt = Pattern.compile("pages = \\{.*\\}",
				Pattern.UNIX_LINES);
		Matcher journalMat = journalPatt.matcher(source);
		while (journalMat.find()) {
			articlePageNumbers = source.substring(journalMat.start(),
					journalMat.end());
		}
		if (articlePageNumbers != "") {
		articlePageNumbers = articlePageNumbers.substring(9,
				articlePageNumbers.length() - 1);
		}
		return articlePageNumbers;
	}

	private String getVolume(String source) {
		String articleVolume = "";
		Pattern volumePatt = Pattern
				.compile("volume = .*,", Pattern.UNIX_LINES);
		Matcher volumeMat = volumePatt.matcher(source);
		while (volumeMat.find()) {
			articleVolume = source
					.substring(volumeMat.start(), volumeMat.end());
		}
		if (articleVolume != "") {
		articleVolume = articleVolume.substring(9, articleVolume.length() - 1);
		}
		return articleVolume;
	}

	@Override
	public Publication call() throws Exception {
		getInformationFromDOI(doi);
		return result;
	}
}
